#include <iostream>
#include <memory>

/* Base class */
class Animal {
public:
    virtual void speak() = 0;
    virtual ~Animal()    = default;
};

class Dog : public Animal {
public:
    void speak() override { std::cout << "Woof!\n" << std::endl; }
};

class Cat : public Animal {
public:
    void speak() override { std::cout << "Meow!\n" << std::endl; }
};

/* Test 1 begin. Basic factory mode. */
std::unique_ptr<Animal> CreateAnimal(const std::string &type)
{
    if (type == "dog")
        return std::make_unique<Dog>();
    if (type == "cat")
        return std::make_unique<Cat>();
    throw std::invalid_argument("Unknown animal type");
}

void test1()
{
    auto animal = CreateAnimal("dog");
    animal->speak();
}

/* TEST 1 end. */

/* Test 2 begin. Factory class + register method. */
template <typename T>
std::unique_ptr<Animal> CreateAnimal2()
{
    return std::make_unique<T>();
}

void test2()
{
    std::string             type = "dog";
    std::unique_ptr<Animal> animal;

    if (type == "dog")
        animal = CreateAnimal2<Dog>();
    else if (type == "cat")
        animal = CreateAnimal2<Cat>();

    if (animal)
        animal->speak();
}

/* Test 2 end. */

int main()
{
    test2();
    return 0;
}